﻿// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/InputSettings.h"
#include "Logging/LogMacros.h"
#include "InputConfigureLibrary.generated.h"


DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnConfigReload);

DECLARE_LOG_CATEGORY_EXTERN(WGI_ConfigFileLog, Log, All);

DECLARE_DYNAMIC_DELEGATE_TwoParams(FOnAnyKeyDown, const FKeyEvent&, InKeyEvent, bool, bIsDown);
DECLARE_DYNAMIC_DELEGATE_OneParam(FOnChangedInputGroup, FString, NewGroupName);

USTRUCT(BlueprintType)
struct WIDGETGROUP_API FActionMappingContainers
{
	GENERATED_BODY()
public:
	FActionMappingContainers();

	UPROPERTY(EditAnywhere, BlueprintReadWrite)
		TArray<FInputActionKeyMapping> Content;
};

class UWGI_UserWidget;

USTRUCT(BlueprintType)
struct WIDGETGROUP_API FInputConfigureGroupData
{
	GENERATED_BODY()
public:
	FInputConfigureGroupData();
	FInputConfigureGroupData(FString inGroupKey);


	UPROPERTY(EditAnywhere, BlueprintReadWrite)
		FString GroupKey;


	/** Enter key configuration .确认键配置 */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FixedInput")
		TArray<FInputActionKeyMapping> EnterAction;
	/** Back key configuration .返回键配置 */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FixedInput")
		TArray<FInputActionKeyMapping> BackAction;

	/** Other key configuration.其他按键配置 */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "OtherInput")
		TMap<FName, FActionMappingContainers> OtherActions;


	void LoadDataAtConfigFile();
	void LoadDataAtConfigFile(FString inNewGroup);
	void LoadFixedInputAtStringArray(const TArray<FString>& inContents);
	void LoadOtherInputAtStringArray(const TArray<FString>& inContents);

	void ConvertToStringArray(TArray<FString>& OutArray);
	void ConvertFixedInputToStringArray(TArray<FString>& OutArray);
	void ConvertOtherInputToStringArray(TArray<FString>& OutArray);

	void ResetData();

	void BindOnConfigReload(UWGI_UserWidget* inWidget);
	void UnBindOnConfigReload(UWGI_UserWidget* inWidget);

	void BindChangedInputGroupEvent(FOnChangedInputGroup inChangedInputGroup);
	void BindAnyKeyDownEvent(FOnAnyKeyDown inAnyKeyDownEvent);
	void CallAnyKeyDownEvent(const FKeyEvent& InKeyEvent, bool bIsDown);
private:
	TArray<UWGI_UserWidget*> OpenedWGIWidget;

	FOnAnyKeyDown AnyKeyDownEvent;
	FOnChangedInputGroup ChangedInputGroup;
};




static class WIDGETGROUP_API InputConfigureLibrary
{
public:
	static void CreateDefaultData(FInputConfigureGroupData& OutData);

	static FString GetConfigFileDir();
	static FString GetPluginBaseDir();
	static void FindInputConfigFiles(TArray<FString>& OutFiles);
	static bool HasAnyInputConfigFile();

	static bool LoadInputConfigFile(const FString filename, TArray<FString>& OutArray);

	static FString ActionsToString(const TArray<FInputActionKeyMapping>& inActions);
	static FString ActionToString(const FInputActionKeyMapping& inAction);
	static void StringToActions(TArray<FInputActionKeyMapping>& OutActions, const FString& ActionsStr);
	static void StringToAction(FInputActionKeyMapping& OutAction, const FString& ActionStr);

	static FString GetDefaultConfigGroupName();
	static void SetDefaultConfigGroupName(FString GroupName);

private:
#if WITH_EDITOR 
	friend FInputConfigureGroupData;

	static FString UpdateCode;
	static void ChackUpdateCode();
	static void SyncUpdateCode();
#endif

	static FInputConfigureGroupData* InputConfigureGroupDataCache;
	static void EnsureDataCacheValid(bool CheckUpdate = true);

public:
	static void ReloadInputConfig(FString GroupName);
	static FString GetCurrentInputConfigName();
	static void CheckReloadToDefaultInputConfig();

	static void BindOnConfigReloadEvent(UWGI_UserWidget* inWidget);
	static void UnBindOnConfigReloadEvent(UWGI_UserWidget* inWidget);
	static bool GetOtherInputKeysFromKeyName(FName inKeyName, TArray<FInputActionKeyMapping>*& OutKeys);

	static bool ThisIsEnterKey(const FKeyEvent& InKeyEvent);
	static bool ThisIsBackKey(const FKeyEvent& InKeyEvent);

	static void BindChangedInputGroupEvent(FOnChangedInputGroup inChangedInputGroup);
	static void BindAnyKeyDownEvent(FOnAnyKeyDown inAnyKeyDownEvent);
	static void CallAnyKeyDownEvent(const FKeyEvent& InKeyEvent, bool bIsDown);
};